﻿using Microsoft.Practices.Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml;
using System.Xml.Serialization;
using System.Threading.Tasks;

namespace HobSoft.SoccerBet2014.Client.ViewModels
{
    using Domain.ClientService;
    using Common;
    using Domain.Models.BfRaw;
    [Serializable]
    [XmlRoot("event")]
    public class BfEvent : CommandViewModel, IDisposable
    {
        #region command
        [XmlIgnore]
        public ICommand UpdateRunnerCommand { get; protected set; }
        [XmlIgnore]
        public ICommand StartRefreshCommand { get; protected set; }
        [XmlIgnore]
        public ICommand StopRefreshCommand { get; protected set; }
        [XmlIgnore]
        public ICommand ShowAllCommand { get; protected set; }
        [XmlIgnore]
        public ICommand ReduceCommand { get; protected set; }
        #endregion

        #region cotr & property

        private DispatcherTimer timer;
        public IBfRequestService BFRequestService { get; set; }
        public bool EnableRefresh { get; set; }
        private double _timerInterval = 1000;
        public double TimerInterval
        {
            get
            {
                return _timerInterval;
            }
            set
            {
                _timerInterval = value;
                timer.Interval = TimeSpan.FromMilliseconds(_timerInterval);
            }
        }
        public BfEvent(IBfRequestService _bfRequestService)
        {
            BFRequestService = _bfRequestService;
            UpdateRunnerCommand = new DelegateCommand(UpdateRunner);
            StartRefreshCommand = new DelegateCommand(StartUpdateRunner);
            StopRefreshCommand = new DelegateCommand(StopUpdateRunner);
            ReduceCommand = new DelegateCommand(ReduceMarket);
            ShowAllCommand = new DelegateCommand(ShowAll);
            RegisterCommand(UpdateRunnerCommand, "更新Runner");
            RegisterCommand(StartRefreshCommand, "开启自动刷新");
            RegisterCommand(StopRefreshCommand, "停止自动刷新");
            RegisterCommand(ReduceCommand, "精简显示");
            RegisterCommand(ShowAllCommand, "全部显示");

            MarketModels = new ObservableCollection<BfMarket>();
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(_timerInterval);
            timer.Tick += Timer_Tick;
        }
        #endregion

        #region event handler
        protected void Timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();
            UpdateRunner();
        }


        private void Game_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "HomeScore" || e.PropertyName == "AwayScore")
            {
                SetScoreFilter();
            }
            else if (e.PropertyName == "Pried")
            {
                SetScoreFilter();
            }
        }

        private void MarketModels_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add
                || e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
            {
                foreach (BfMarket item in e.NewItems)
                {
                    item.PropertyChanged += Market_PropertyChanged;
                    item.Event = this;
                }
            }
        }

        private void Market_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "FocusRunner")
            {
                var mk = sender as BfMarket;
                HasFocus = MarketModels.Any(m => m.HasFocus);
                if (mk == null || !mk.HasFocus)
                {
                    FocusRunner = null;
                    return;
                }
                FocusRunner = mk.FocusRunner;
                foreach (var item in MarketModels)
                {
                    if (item != mk && item.HasFocus)
                        item.BlurRunner();
                }
            }
        }
        #endregion

        #region imple command
        public void StartUpdateRunner()
        {
            EnableRefresh = true;
            if (!timer.IsEnabled)
                timer.Start();
        }
        public void StopUpdateRunner()
        {
            if (timer.IsEnabled)
                timer.Stop();
            EnableRefresh = false;
        }
        public void UpdateRunner()
        {
            if (BFRequestService == null)
                return;
            if (MarketModels == null || !MarketModels.Any()) return;
            RaiseCommandStart(UpdateRunnerCommand, "开始更新Runner");
            var marketIds = MarketModels.Select(m => m.MarketID).ToArray();
            BFRequestService.GetMarketBook(marketIds).ContinueWith(t =>
            {
                Application.Current.Dispatcher.Invoke(new Action(delegate()
                {
                    RaiseCommandOver(UpdateRunnerCommand);
                    if (EnableRefresh)
                        timer.Start();
                    if (t.IsCanceled || t.Exception != null)
                    {
                        RaiseDispatcherCommandError(t.Exception);
                        return;
                    }
                    var result = t.Result;
                    MappingMarketBook(result);
                }));
            });
        }

        protected void ReduceMarket()
        {
            foreach (var market in MarketModels)
            {
                if (reduceCategory.Contains(market.MarketCategory))
                    market.IsFilter = false;
                else
                    market.IsFilter = true;
            }
        }

        protected void ShowAll()
        {
            foreach (var market in MarketModels)
            {
                market.IsFilter = false;
            }
            SetScoreFilter();
        }

        #endregion

        #region local method
        protected void MappingMarketBook(IList<MarketBook> marketBooks)
        {
            if (marketBooks == null || !marketBooks.Any()) return;
            foreach (var mb in marketBooks)
            {
                try
                {
                    var market = MarketModels.FirstOrDefault(m => m.MarketID == mb.MarketId);
                    if (market == null) continue;
                    AutoMapper.Mapper.Map(mb, market);
                    if (market.MarketCategory == 11)
                    {
                        if (market.MarketStatus.Equals("CLOSE", StringComparison.OrdinalIgnoreCase))
                        {
                            GameState = "CLOSE";
                        }
                    }
                    foreach (var runner in market.Runners)
                    {
                        var upRunner = mb.Runners.FirstOrDefault(r => r.SelectionId == runner.SelectionID);
                        if (upRunner == null) continue;
                        AutoMapper.Mapper.Map(upRunner, runner);
                    }
                }
                catch (Exception ex)
                {
                    RaiseCommandError(ex);
                }
            }

        }


        protected void SetScoreFilter()
        {
            foreach (var item in marketOUFilter)
            {
                var market = MarketModels.FirstOrDefault(m => m.MarketCategory == item.Key);
                if (market != null)
                {
                    var totalScore = Game.HomeScore + Game.AwayScore;
                    if (item.Value > totalScore && item.Value < totalScore + 2)
                        market.IsFilter = false;
                    else
                        market.IsFilter = true;
                }
            }
            if (Game.Pried > 1)
            {
                var preidMarkets = MarketModels.Where(m => m.MarketCategory <= 4);
                foreach (var market in preidMarkets)
                {
                    market.IsFilter = true;
                }
            }

            var scoreMarkets = MarketModels.Where(m => m.MarketCategory == 4 || m.MarketCategory == 31 || m.MarketCategory == 32 || m.MarketCategory == 33);
            foreach (var market in scoreMarkets)
            {
                market.BlockViewRefresh = true;
                foreach (var rn in market.Runners)
                {
                    var rnName = rn.RunnerName;
                    var matchScore = regRunnerScore.Match(rnName);
                    if (matchScore.Success && matchScore.Groups["h"].Success && matchScore.Groups["a"].Success)
                    {
                        byte hScore = 0, aScore;
                        byte.TryParse(matchScore.Groups["h"].Value, out hScore);
                        byte.TryParse(matchScore.Groups["a"].Value, out aScore);

                        if (hScore >= Game.HomeScore && hScore <= Game.HomeScore + 1
                            && aScore >= Game.AwayScore && aScore <= Game.AwayScore + 1)
                            rn.IsFilter = false;
                        else
                            rn.IsFilter = true;
                    }
                }
                market.BlockViewRefresh = false;
                if (!market.IsFilter)
                {
                    if (!market.RunnersView.SortDescriptions.Any(s => s.PropertyName == "OrderIndex"))
                        market.RunnersView.SortDescriptions.Add(new SortDescription("OrderIndex", ListSortDirection.Ascending));
                    market.RunnersView.Refresh();
                }
            }
        }

        #endregion

        #region model property
        private int _eventID;
        [XmlAttribute("event-id")]
        public int EventID
        {
            get { return _eventID; }
            set { PropertyValueChange(ref _eventID, value, "EventID"); }
        }

        private string _homeTeam;
        [XmlAttribute("home-team")]
        public string HomeTeam
        {
            get { return _homeTeam; }
            set { PropertyValueChange(ref _homeTeam, value, "HomeTeam"); }
        }

        private string _awayTeam;
        [XmlAttribute("away-team")]
        public string AwayTeam
        {
            get { return _awayTeam; }
            set { PropertyValueChange(ref _awayTeam, value, "AwayTeam"); }
        }

        private byte _homeScore;
        [XmlAttribute("home-score")]
        public byte HomeScore
        {
            get { return _homeScore; }
            set { PropertyValueChange(ref _homeScore, value, "HomeScore"); }
        }

        private byte _awayScore;
        [XmlAttribute("away-score")]
        public byte AwayScore
        {
            get { return _awayScore; }
            set { PropertyValueChange(ref _awayScore, value, "AwayScore"); }
        }

        private string _path;
        [XmlElement("path")]
        public string Path
        {
            get { return _path; }
            set { PropertyValueChange(ref _path, value, "Path"); }
        }

        private DateTime _startTime;
        [XmlElement("start-time")]
        public DateTime StartTime
        {
            get { return _startTime; }
            set { PropertyValueChange(ref _startTime, value, "StartTime"); }
        }

        private string _gameState;
        [XmlElement("game-state")]
        public string GameState
        {
            get { return _gameState; }
            set { PropertyValueChange(ref _gameState, value, "GameState"); }
        }

        private string _timeState;
        [XmlElement("time-state")]
        public string TimeState
        {
            get { return _timeState; }
            set { PropertyValueChange(ref _timeState, value, "TimeState"); }
        }

        private ObservableCollection<BfMarket> _marketModels;
        [XmlElement("market")]
        public ObservableCollection<BfMarket> MarketModels
        {
            get { return _marketModels; }
            set
            {
                PropertyValueChange(ref _marketModels, value, "MarketModels");
                if (_marketModels != null)
                {
                    foreach (BfMarket item in _marketModels)
                    {
                        item.PropertyChanged += Market_PropertyChanged;
                        item.Event = this;
                    }
                    _marketModels.CollectionChanged += MarketModels_CollectionChanged;
                }
            }
        }

        #endregion

        public void BlurRunner()
        {
            HasFocus = false;
            FocusRunner = null;
            foreach (var mk in MarketModels)
            {
                if (mk.HasFocus)
                    mk.BlurRunner();
            }
        }

        private long _version;
        [XmlIgnore]
        public long Version
        {
            get { return _version; }
            set { PropertyValueChange(ref _version, value, "Version"); }
        }

        private Game _game;
        [XmlIgnore]
        public Game Game
        {
            get { return _game; }
            set
            {
                PropertyValueChange(ref _game, value, "Game");
                if (_game != null)
                {
                    SetScoreFilter();
                    _game.PropertyChanged += Game_PropertyChanged;
                }
            }
        }

        private Runner _focusRunner;
        [XmlIgnore]
        public Runner FocusRunner
        {
            get { return _focusRunner; }
            set { PropertyValueChange(ref _focusRunner, value, "FocusRunner"); }
        }

        private bool _hasFocus;
        [XmlIgnore]
        public bool HasFocus
        {
            get { return _hasFocus; }
            set { PropertyValueChange(ref _hasFocus, value, "HasFocus"); }
        }

        Dictionary<byte, decimal> marketOUFilter = new Dictionary<byte, decimal>()
        {
            {2, 0.5m},
            {3, 1.5m},
            {20,0.5m},
            {21,1.5m},
            {22,2.5m},
            {23,3.5m},
            {24,4.5m},
            {25,5.5m},
            {26,6.5m},
            {27,7.5m},
            {28,8.5m}
        };
        byte[] reduceCategory = new byte[] { 1, 11, 22 };
        
        Regex regRunnerScore = new Regex(@"(?<h>\d)\s*\-\s*(?<a>\d)", RegexOptions.Compiled);
        public void Dispose()
        {
            if (timer != null && timer.IsEnabled)
            {
                timer.Stop();
            }
        }
    }

}
